# 作者：詹广权
# 版权所有：www.cdsjcc.cn/su-xz
# 说明：线转槽
# 功能：将线转换为3D凹槽，支持不同位置、深度和宽度的凹槽创建。

require 'sketchup.rb'
require File.join(File.dirname(__FILE__), 'cs.rb')

module SuXZ
  module KC
    
    # 常量定义
    Z_AXIS = Geom::Vector3d.new(0, 0, 1)
    
    # 主功能：生成凹槽
    def self.create_groove(edges, depth, width, position, inward = true, pick_paths = nil)
      model = Sketchup.active_model
      
      # 添加调试输出，显示参数值
      puts "创建凹槽使用参数: 深度=#{depth}, 宽度=#{width}, 位置=#{position}, 朝向=#{inward ? '向内' : '向外'}"
      
      # 确保深度和宽度是浮点数
      if depth.is_a?(String)
        depth = depth.to_f.mm
      end
      
      if width.is_a?(String)
        width = width.to_f.mm
      end
      
      edges.each_with_index do |edge, index|
        # 确保边线有效
        unless edge && edge.valid?
          puts "错误：边线无效或已被删除"
          next
        end
        
        # 确定边线所在的编辑上下文
        pick_path = pick_paths && index < pick_paths.length ? pick_paths[index] : nil
        container = nil
        parent_entities = model.active_entities
        
        # 如果有拾取路径，找到边线所属的容器（组或组件）
        if pick_path && pick_path.length > 1
          puts "处理拾取路径: #{pick_path.inspect}"
          
          # 遍历路径找到容器
          containers = pick_path.select { |entity| 
            entity.is_a?(Sketchup::Group) || entity.is_a?(Sketchup::ComponentInstance)
          }
          
          if !containers.empty?
            # 使用最内部的容器（最后一个）
            container = containers.last
            puts "找到容器: #{container.class.name} #{container.entityID}"
            
            if container.is_a?(Sketchup::Group)
              parent_entities = container.entities
              puts "设置父实体为群组，实体数量: #{parent_entities.size}"
            elsif container.is_a?(Sketchup::ComponentInstance)
              parent_entities = container.definition.entities
              puts "设置父实体为组件，实体数量: #{parent_entities.size}"
            end
          end
        end
        
        # 查找边线关联的面
        face = edge.faces.first
        if !face || !face.valid?
          puts "错误：边线没有关联的有效面"
          next
        else
          puts "找到关联面: #{face.entityID}, 面积: #{face.area}"
        end
        
        # 获取边线的方向向量
        edge_vector = edge.line[1].normalize
        puts "边线向量: #{edge_vector.to_s}"
        
        # 计算偏移方向向量 (垂直于边线且在面内)
        offset_vector = face.normal * edge_vector
        puts "计算偏移向量: #{offset_vector.to_s}, 面法向量: #{face.normal.to_s}"
        
        # 获取正确的变换矩阵用于坐标转换
        transformation = nil
        if container
          # 如果边线在组或组件内，使用容器的变换
          transformation = container.transformation
          puts "使用容器变换: #{transformation.to_a.inspect}"
        end
        
        case position
        when "右边"
          # 设置偏移向量长度为凹槽宽度 - 确保使用浮点数
          offset_vector.length = width.to_f
          puts "设置偏移向量长度为: #{width}"
          
          # 检查偏移方向
          test_point = edge.start.position.offset(offset_vector)
          if face.classify_point(test_point) != Sketchup::Face::PointOutside
            # 如果偏移点不在面外，则翻转向量，确保它朝面外
            offset_vector.reverse!
          end
          
          # 根据用户设置的朝向决定最终方向
          if inward
            # 用户选择向内，需要翻转向量
            puts "用户设置为向内，翻转向量"
            offset_vector.reverse!
          end
          
          # 创建凹槽路径的点
          offset_start_point = edge.start.position.offset(offset_vector)
          offset_end_point = edge.end.position.offset(offset_vector)
          
          # 创建凹槽面
          begin
            points = [
              edge.start.position,
              edge.end.position,
              offset_end_point,
              offset_start_point
            ]
            
            puts "原始点: #{points.map(&:to_s).join(', ')}"
            
            # 如果在组或组件内创建，需要转换坐标
            if transformation && !transformation.identity?
              # 将点从全局坐标转换为本地坐标
              local_points = points.map { |pt| transformation.inverse * pt }
              puts "转换后的点: #{local_points.map(&:to_s).join(', ')}"
              puts "尝试在父实体中创建面..."
              groove_face = parent_entities.add_face(local_points)
              puts groove_face ? "面创建成功，ID: #{groove_face.entityID}" : "错误：面创建失败！"
            else
              # 直接在模型中创建
              puts "尝试在模型中创建面..."
              groove_face = parent_entities.add_face(points)
              puts groove_face ? "面创建成功，ID: #{groove_face.entityID}" : "错误：面创建失败！"
            end
            
            # 推拉形成凹槽
            if groove_face && groove_face.valid?
              puts "面创建成功，进行推拉操作"
              # 使用负值进行推拉 - 确保使用浮点数
              distance = -depth.to_f
              # 如果需要，调整推拉方向以匹配容器的变换
              if transformation && !transformation.identity?
                # 计算调整后的深度方向，考虑容器变换
                depth_factor = transformation.xaxis.dot(Z_AXIS) >= 0 ? 1 : -1
                puts "深度调整因子: #{depth_factor}"
                distance = distance * depth_factor
              end
              puts "准备推拉面，距离: #{distance}"
              begin
                result = groove_face.pushpull(distance)
                puts "推拉操作完成，返回结果: #{result}"
              rescue => e
                puts "推拉操作出错: #{e.message}\n#{e.backtrace.join("\n")}"
              end
            else
              puts "错误：无法创建有效的面 (groove_face是否为nil? #{groove_face.nil?})"
            end
          rescue => e
            puts "创建凹槽出错: #{e.message}\n#{e.backtrace.join("\n")}"
          end
          
        when "左边"
          # 偏移向量长度为凹槽宽度 - 确保使用浮点数
          offset_vector.length = width.to_f
          puts "设置偏移向量长度为: #{width} (左边)"
          
          # 首先确保向量是朝面外的
          test_point = edge.start.position.offset(offset_vector)
          if face.classify_point(test_point) != Sketchup::Face::PointOutside
            # 如果偏移点不在面外，则翻转向量，确保它朝面外
            offset_vector.reverse!
          end
          
          # 根据用户设置的朝向决定最终方向
          if inward
            # 用户选择向内，需要翻转向量
            puts "用户设置为向内，翻转向量"
            offset_vector.reverse!
          end
          
          # 创建凹槽路径的点
          offset_start_point = edge.start.position.offset(offset_vector)
          offset_end_point = edge.end.position.offset(offset_vector)
          
          # 创建凹槽面
          begin
            points = [
              edge.start.position,
              edge.end.position,
              offset_end_point,
              offset_start_point
            ]
            
            puts "原始点(左边): #{points.map(&:to_s).join(', ')}"
            
            # 如果在组或组件内创建，需要转换坐标
            if transformation && !transformation.identity?
              # 将点从全局坐标转换为本地坐标
              local_points = points.map { |pt| transformation.inverse * pt }
              puts "转换后的点: #{local_points.map(&:to_s).join(', ')}"
              puts "尝试在父实体中创建面..."
              groove_face = parent_entities.add_face(local_points)
              puts groove_face ? "面创建成功，ID: #{groove_face.entityID}" : "错误：面创建失败！"
            else
              # 直接在模型中创建
              puts "尝试在模型中创建面..."
              groove_face = parent_entities.add_face(points)
              puts groove_face ? "面创建成功，ID: #{groove_face.entityID}" : "错误：面创建失败！"
            end
            
            # 推拉形成凹槽
            if groove_face && groove_face.valid?
              puts "面创建成功，进行推拉操作"
              # 使用负值进行推拉 - 确保使用浮点数
              distance = -depth.to_f
              # 如果需要，调整推拉方向以匹配容器的变换
              if transformation && !transformation.identity?
                # 计算调整后的深度方向，考虑容器变换
                depth_factor = transformation.xaxis.dot(Z_AXIS) >= 0 ? 1 : -1
                puts "深度调整因子: #{depth_factor}"
                distance = distance * depth_factor
              end
              puts "准备推拉面，距离: #{distance}"
              begin
                result = groove_face.pushpull(distance)
                puts "推拉操作完成，返回结果: #{result}"
              rescue => e
                puts "推拉操作出错: #{e.message}\n#{e.backtrace.join("\n")}"
              end
            else
              puts "错误：无法创建有效的面 (groove_face是否为nil? #{groove_face.nil?})"
            end
          rescue => e
            puts "创建凹槽出错: #{e.message}\n#{e.backtrace.join("\n")}"
          end
          
        when "中间"
          # 对于中间位置，需要在边线两侧创建凹槽
          # 凹槽宽度的一半作为偏移距离 - 确保使用浮点数
          offset_vector.length = (width / 2.0).to_f
          puts "设置偏移向量长度为: #{width/2.0} (中间)"
          
          # 默认中间位置的一侧偏移方向为面法向量方向
          # 首先确保向量是朝面外的
          test_point = edge.start.position.offset(offset_vector)
          inside_test = face.classify_point(test_point)
          puts "点在面内部判断结果: #{inside_test} (#{Sketchup::Face::PointUnknown}/#{Sketchup::Face::PointInside}/#{Sketchup::Face::PointOnFace}/#{Sketchup::Face::PointOutside})"
          
          if inside_test != Sketchup::Face::PointOutside
            # 如果偏移点不在面外，则翻转向量，确保它朝面外
            puts "调整向量方向：朝面外"
            offset_vector.reverse!
          end
          
          # 根据用户设置的朝向决定最终方向
          if inward
            # 用户选择向内，需要翻转向量
            puts "用户设置为向内，翻转向量"
            offset_vector.reverse!
          else
            puts "用户设置为向外，保持向量朝外"
          end
          
          # 创建一侧的偏移点
          offset_start_point1 = edge.start.position.offset(offset_vector)
          offset_end_point1 = edge.end.position.offset(offset_vector)
          
          # 创建另一侧的偏移点（反向）
          offset_vector.reverse!
          offset_start_point2 = edge.start.position.offset(offset_vector)
          offset_end_point2 = edge.end.position.offset(offset_vector)
          
          # 创建凹槽面
          begin
            points = [
              offset_start_point2,
              offset_end_point2,
              offset_end_point1,
              offset_start_point1
            ]
            
            puts "原始点(中间): #{points.map(&:to_s).join(', ')}"
            
            # 如果在组或组件内创建，需要转换坐标
            if transformation && !transformation.identity?
              # 将点从全局坐标转换为本地坐标
              local_points = points.map { |pt| transformation.inverse * pt }
              puts "转换后的点: #{local_points.map(&:to_s).join(', ')}"
              puts "尝试在父实体中创建面..."
              groove_face = parent_entities.add_face(local_points)
              puts groove_face ? "面创建成功，ID: #{groove_face.entityID}" : "错误：面创建失败！"
            else
              # 直接在模型中创建
              puts "尝试在模型中创建面..."
              groove_face = parent_entities.add_face(points)
              puts groove_face ? "面创建成功，ID: #{groove_face.entityID}" : "错误：面创建失败！"
            end
            
            # 推拉形成凹槽
            if groove_face && groove_face.valid?
              puts "面创建成功，进行推拉操作"
              # 使用负值进行推拉 - 确保使用浮点数
              distance = -depth.to_f
              # 如果需要，调整推拉方向以匹配容器的变换
              if transformation && !transformation.identity?
                # 计算调整后的深度方向，考虑容器变换
                depth_factor = transformation.xaxis.dot(Z_AXIS) >= 0 ? 1 : -1
                puts "深度调整因子: #{depth_factor}"
                distance = distance * depth_factor
              end
              puts "准备推拉面，距离: #{distance}"
              begin
                result = groove_face.pushpull(distance)
                puts "推拉操作完成，返回结果: #{result}"
              rescue => e
                puts "推拉操作出错: #{e.message}\n#{e.backtrace.join("\n")}"
              end
            else
              puts "错误：无法创建有效的面 (groove_face是否为nil? #{groove_face.nil?})"
            end
          rescue => e
            puts "创建凹槽出错: #{e.message}\n#{e.backtrace.join("\n")}"
          end
        end
      end
      
      return true
    end
    
    # 从选中对象创建凹槽，支持默认参数
    def self.create_groove_from_selection(depth = nil, width = nil, position = nil, inward = nil, pick_path = nil)
      # 如果未提供参数，则使用CS模块获取设置
      settings = SuXZ::CS.get_settings('KC')
      depth ||= settings['depth']
      width ||= settings['width']
      position ||= settings['position']
      inward = inward.nil? ? settings['inward'] : inward
      
      # 确保深度和宽度是浮点数
      if depth.is_a?(String)
        depth = depth.to_f.mm
      end
      
      if width.is_a?(String)
        width = width.to_f.mm
      end
      
      selection = Sketchup.active_model.selection
      edges = selection.grep(Sketchup::Edge)
      
      if edges.empty?
        UI.messagebox("请先选择边线！")
        return false
      else
        # 开始一个事务
        model = Sketchup.active_model
        model.start_operation("线转槽", true)
        
        begin
          # 传递拾取路径给create_groove方法
          pick_paths = pick_path ? [pick_path] : nil
          self.create_groove(edges, depth, width, position, inward, pick_paths)
          model.commit_operation
          return true
        rescue => e
          model.abort_operation
          puts "从选择创建凹槽时出错: #{e.message}\n#{e.backtrace.join("\n")}"
          return false
        end
      end
    end
    
    # 检查选中的边线是否适合创建凹槽
    def self.check_selected_edges
      selection = Sketchup.active_model.selection
      edges = selection.grep(Sketchup::Edge)
      
      if edges.empty?
        UI.messagebox("未选择边线！请先选择边线。")
        return false
      end
      
      valid_edges = 0
      invalid_edges = 0
      
      edges.each do |edge|
        if edge.faces.first
          valid_edges += 1
        else
          invalid_edges += 1
        end
      end
      
      message = "检查结果：\n"
      message << "- 共选择 #{edges.length} 条边线\n"
      message << "- 有效边线（附着在面上）: #{valid_edges}\n"
      message << "- 无效边线（未附着在面上）: #{invalid_edges}\n\n"
      
      if invalid_edges > 0
        message << "提示：只有附着在面上的边线才能创建凹槽。"
      else
        message << "所有选中的边线都可以用来创建凹槽。"
      end
      
      UI.messagebox(message)
      return (invalid_edges == 0)
    end
    
    # 直接使用边线对象创建凹槽（用于组和组件内部的边线）
    def self.create_groove_directly(edge, depth = nil, width = nil, position = nil, inward = nil, pick_path = nil)
      # 如果未提供参数，则使用CS模块获取设置
      settings = SuXZ::CS.get_settings('KC')
      depth ||= settings['depth']
      width ||= settings['width']
      position ||= settings['position']
      inward = inward.nil? ? settings['inward'] : inward
      
      # 确保深度和宽度是浮点数
      if depth.is_a?(String)
        depth = depth.to_f.mm
      end
      
      if width.is_a?(String)
        width = width.to_f.mm
      end
      
      # 验证边线
      unless edge.is_a?(Sketchup::Edge) && edge.valid?
        puts "错误：提供的边线对象无效"
        return false
      end
      
      # 创建一个只包含这条边线的数组
      edges = [edge]
      
      # 创建一个只包含这条边线路径的数组
      pick_paths = pick_path ? [pick_path] : nil
      
      # 启动一个新的事务
      model = Sketchup.active_model
      model.start_operation("线转槽", true)
      
      # 确认是否需要进入编辑上下文
      needs_context_switch = false
      original_active_path = nil
      container = nil
      
      begin
        # 如果有拾取路径，并且是在组或组件内
        if pick_path && pick_path.length > 1
          containers = pick_path.select { |entity| 
            entity.is_a?(Sketchup::Group) || entity.is_a?(Sketchup::ComponentInstance)
          }
          
          if !containers.empty?
            container = containers.last
            puts "发现容器，检查是否需要进入编辑上下文: #{container.class.name} #{container.entityID}"
            
            # 检查是否已经在此编辑上下文中
            original_active_path = model.active_path
            
            if original_active_path != pick_path[0...-1]
              needs_context_switch = true
              puts "需要进入编辑上下文"
              
              # 尝试进入编辑上下文
              begin
                model.active_path = pick_path[0...-1]
                puts "已进入编辑上下文: #{model.active_path.inspect}"
              rescue => e
                puts "进入编辑上下文失败: #{e.message}"
                # 如果无法进入编辑上下文，回退到原来的方法
                needs_context_switch = false
              end
            else
              puts "已经在正确的编辑上下文中"
            end
          end
        end
        
        # 根据是否切换了上下文，选择合适的方法创建凹槽
        if needs_context_switch
          # 在当前活动上下文中创建凹槽
          puts "在编辑上下文中创建凹槽"
          parent_entities = model.active_entities
          
          # 定义几何点
          case position
          when "右边"
            # 获取边线的相关几何数据
            face = edge.faces.first
            unless face && face.valid?
              puts "错误：找不到有效的面"
              model.abort_operation
              return false
            end
            
            # 计算方向向量
            edge_vector = edge.line[1].normalize
            offset_vector = face.normal * edge_vector
            
            # 设置偏移向量长度 - 确保使用浮点数
            offset_vector.length = width.to_f
            
            # 检查偏移方向
            test_point = edge.start.position.offset(offset_vector)
            if face.classify_point(test_point) != Sketchup::Face::PointOutside
              # 如果偏移点不在面外，则翻转向量，确保它朝面外
              offset_vector.reverse!
            end
            
            # 根据用户设置的朝向决定最终方向
            if inward
              # 用户选择向内，需要翻转向量
              offset_vector.reverse!
            end
            
            # 创建点
            offset_start_point = edge.start.position.offset(offset_vector)
            offset_end_point = edge.end.position.offset(offset_vector)
            points = [
              edge.start.position,
              edge.end.position,
              offset_end_point,
              offset_start_point
            ]
          when "左边"
            # 获取边线的相关几何数据
            face = edge.faces.first
            unless face && face.valid?
              puts "错误：找不到有效的面"
              model.abort_operation
              return false
            end
            
            # 计算方向向量
            edge_vector = edge.line[1].normalize
            offset_vector = face.normal * edge_vector
            
            # 设置偏移向量长度 - 确保使用浮点数
            offset_vector.length = width.to_f
            
            # 首先确保向量是朝面外的
            test_point = edge.start.position.offset(offset_vector)
            if face.classify_point(test_point) != Sketchup::Face::PointOutside
              # 如果偏移点不在面外，则翻转向量，确保它朝面外
              offset_vector.reverse!
            end
            
            # 根据用户设置的朝向决定最终方向
            if inward
              # 用户选择向内，需要翻转向量
              offset_vector.reverse!
            end
            
            # 创建点
            offset_start_point = edge.start.position.offset(offset_vector)
            offset_end_point = edge.end.position.offset(offset_vector)
            points = [
              edge.start.position,
              edge.end.position,
              offset_end_point,
              offset_start_point
            ]
          when "中间"
            # 获取边线的相关几何数据
            face = edge.faces.first
            unless face && face.valid?
              puts "错误：找不到有效的面"
              model.abort_operation
              return false
            end
            
            # 计算方向向量
            edge_vector = edge.line[1].normalize
            offset_vector = face.normal * edge_vector
            
            # 设置偏移向量长度（一半宽度）- 确保使用浮点数
            offset_vector.length = (width / 2.0).to_f
            
            # 首先确保向量是朝面外的
            test_point = edge.start.position.offset(offset_vector)
            if face.classify_point(test_point) != Sketchup::Face::PointOutside
              # 如果偏移点不在面外，则翻转向量，确保它朝面外
              offset_vector.reverse!
            end
            
            # 根据用户设置的朝向决定最终方向
            if inward
              # 用户选择向内，需要翻转向量
              offset_vector.reverse!
            end
            # 向外时保持向量朝外
            
            # 创建一侧点
            offset_start_point1 = edge.start.position.offset(offset_vector)
            offset_end_point1 = edge.end.position.offset(offset_vector)
            
            # 创建另一侧点
            opposite_vector = offset_vector.clone.reverse!
            offset_start_point2 = edge.start.position.offset(opposite_vector)
            offset_end_point2 = edge.end.position.offset(opposite_vector)
            
            # 创建点数组
            points = [
              offset_start_point2,
              offset_end_point2,
              offset_end_point1,
              offset_start_point1
            ]
          end
          
          # 创建面并推拉
          begin
            puts "尝试在编辑上下文中创建面，点数: #{points.length}"
            groove_face = parent_entities.add_face(points)
            
            if groove_face && groove_face.valid?
              puts "面创建成功，ID: #{groove_face.entityID}"
              puts "准备推拉面，深度: #{depth}"
              # 确保使用浮点数进行推拉
              groove_face.pushpull(-depth.to_f) # 使用负值推拉
              puts "推拉完成"
            else
              puts "错误：面创建失败"
            end
          rescue => e
            puts "在编辑上下文中创建凹槽出错: #{e.message}\n#{e.backtrace.join("\n")}"
            model.abort_operation
            return false
          ensure
            # 恢复原始编辑上下文
            if original_active_path != model.active_path
              model.active_path = original_active_path
              puts "已恢复原始编辑上下文"
            end
          end
        else
          # 使用原来的方法创建凹槽
          puts "使用标准方法创建凹槽"
          # 调用原始创建方法
          self.create_groove(edges, depth, width, position, inward, pick_paths)
        end
        
        model.commit_operation
        return true
      rescue => e
        puts "创建凹槽过程中出错: #{e.message}\n#{e.backtrace.join("\n")}"
        model.abort_operation
        return false
      end
    end
    
    # 初始化
    def self.init
      puts "线转槽模块已加载"
    end
  end

  # 初始化KC模块
  KC.init
end